diff -c -r bind4.9.orig/CHANGES bind4.9/CHANGES
*** bind4.9.orig/CHANGES	Sun May  2 20:16:48 1993
--- bind4.9/CHANGES	Fri May 21 14:32:27 1993
***************
*** 1,3 ****
--- 1,28 ----
+ 4.9.1-UMICH -------------------
+ 
+ This patch fixs a bug in the resolver library, and adds two new RR types:
+ AFSDB and SA.
+ 
+ The resolver bug is one in res_debug.c that is exercised by large queries
+ (i.e., queries that will end up using TCP instead of UDP).
+ 
+ AFSDB records are used to list AFS cell databases.  The RR is defined in 
+ RFC 1183.
+ 
+ SA records are "shuffle address" records, and are not at all standard.  They
+ are an option (see OPTIONS and conf/options.h) which allows one to use a new
+ type of A record which is randomized (shuffled) before being returned.  We
+ use them at the University of Michigan for domain names like hermes.merit.edu
+ and msdos.archive.umich.edu.
+ 
+ Also, the query program in the umich part of the contrib directory needed a
+ small change to work with the new BIND 4.9 resolver library.
+ 
+ And finally, this patch adds a feature called TRY_AS_IS which causes the
+ resolver library to try a given name 'as is' if it contains two or more
+ dots before tacking on any domain names.  We have found that this 
+ drastically reduces the number of local domain packets.
+ 
  4.9-FINAL -------------------
  
  Kevin Dunlap sent in some changes for the BOG.  So did a lot of other folks.
diff -c -r bind4.9.orig/OPTIONS bind4.9/OPTIONS
*** bind4.9.orig/OPTIONS	Sun May  2 20:16:49 1993
--- bind4.9/OPTIONS	Fri Jun 18 14:02:11 1993
***************
*** 209,214 ****
--- 209,235 ----
  and you are interested in a more predictable and sensible interpretation of
  dotted numbers, then you probably want this.
  
+ SHUFFLE_ADDRS (origin: Bryan Beecher of UMich)
+ 	if set, allows the use of shuffle address (SA) records.  these are
+ one method for "DNS load balancing" since groups of these records are
+ shuffled (randomized) before being returned.  these are currently in use
+ at the University of Michigan for names like msdos.archive.umich.edu.
+ 	you probably want this since the added code is minimal, and it will
+ allow you to use SA records if you decide you want to one day.
+ 
+ TRY_AS_IS (origin: Bryan Beecher of UMich)
+ 	if set, the resolver library will try a name 'as is'  -- if it contains
+ two or more dots -- before trying the name by appending any domains.  This is
+ something that we have used for a long time, and it really seems to cut down
+ on the number of local domain packets.
+ 	you probably want this
+ 
+ LAME_DELEGATION (origin: Don Lewis of Harris)
+ 	if set, logs lame delegations.  A lame delegation is a case when a
+ nameserver is listed as authoritative for a domain (via a NS record), yet
+ when queried on names within that domain, it returns non-authoritative data.
+ 	you might want this if you want to harrass "lamers"
+ 
  ## ++Copyright++ 1989
  ## -
  ## Copyright (c) 1989 Regents of the University of California.
diff -c -r bind4.9.orig/TODO bind4.9/TODO
*** bind4.9.orig/TODO	Mon May 17 06:00:10 1993
--- bind4.9/TODO	Fri May 21 14:13:37 1993
***************
*** 86,116 ****
  	(dropping the TTL down low as a "<[date]" approaches,
  	and forcing a new zone transfer at "date").
  
- [Paul:  I know you said that you'd like to wait for the IETF DNS WG to "bless"
- an official load balancing scheme, but I'll be adding my shuffle A records to
- BIND 4.9 for use here at U-M anyhow.  The code mods to existing source files
- are minimal since the bulk of the work is done in a separate .c I added.
- If you don't want SA records to move into 4.9.1 unless they become official,
- please just toss this first entry. --bryan@umich.edu]
- 
- [bryan@umich.edu 25apr93]: add "shuffle A" records
- 	There are several schemes for adding some kind of load balancing
- 	capability to the DNS.  Our "Shuffle Address" (SA) records are one
- 	stab at this, and since they're in use at U-M, I need to add them
- 	so we can use BIND 4.9 here.
- 
- [bryan@umich.edu 25apr93]: add AFSDB records
- 	AFSDB records were proposed in RFC xxxx.  We use them here at the
- 	University of Michigan, so I need to add them for our copy of
- 	BIND 4.9.
- 
- [bryan@umich.edu 25apr93]: small fix to resolver's p_cdname()
- 	The current copy of p_cdname() in the resolver does not work
- 	for query responses larger than 512 bytes (which can happen when
- 	using TCP).  A very small modification changes the "sanity check"
- 	argument (the second one) to dn_expand() from "msg + 512" to
- 	"cp + MAXCDNAME".  (This showed up very recently.)
- 
  [gshapiro@wpi.wpi.edu and vixie@pa.dec.com 26apr93]: access control
  	"xfrnets" is ok but what we really need is full access control per
  	zone rather than a global list of acceptable client nets.  this is
--- 86,91 ----
Common subdirectories: bind4.9.orig/bin and bind4.9/bin
Common subdirectories: bind4.9.orig/conf and bind4.9/conf
Common subdirectories: bind4.9.orig/contrib and bind4.9/contrib
Common subdirectories: bind4.9.orig/doc and bind4.9/doc
Common subdirectories: bind4.9.orig/include and bind4.9/include
Common subdirectories: bind4.9.orig/man and bind4.9/man
Common subdirectories: bind4.9.orig/master and bind4.9/master
Common subdirectories: bind4.9.orig/named and bind4.9/named
Only in bind4.9: native.b
Common subdirectories: bind4.9.orig/res and bind4.9/res
Common subdirectories: bind4.9.orig/tools and bind4.9/tools
diff -c -r bind4.9.orig/conf/options.h bind4.9/conf/options.h
*** bind4.9.orig/conf/options.h	Sun May  2 19:17:42 1993
--- bind4.9/conf/options.h	Wed Jun 16 15:28:19 1993
***************
*** 92,97 ****
--- 92,100 ----
  #define WANT_PIDFILE	/* if you want the named.pid file (ucb/arc) */
  #define DOTTED_SERIAL	/* if you want to be able to specify dotted serial#s */
  /*#define SENSIBLE_DOTS	/* if you want dotted serial#s to make numeric sense */
+ #define SHUFFLE_ADDRS	/* if you want to use shuffle address records (bb) */
+ #define TRY_AS_IS	/* try names 'as is' if they have 2+ dots (bb) */
+ #define LAME_DELEGATION /* log detected lame delegations (bb) */
  
  /*--------------------------------------------*
   * no user-servicable parts beyond this point *
Common subdirectories: bind4.9.orig/contrib/ckdns and bind4.9/contrib/ckdns
Common subdirectories: bind4.9.orig/contrib/decwrl and bind4.9/contrib/decwrl
Common subdirectories: bind4.9.orig/contrib/dnsparse and bind4.9/contrib/dnsparse
Common subdirectories: bind4.9.orig/contrib/doc-2.0 and bind4.9/contrib/doc-2.0
Common subdirectories: bind4.9.orig/contrib/host and bind4.9/contrib/host
Common subdirectories: bind4.9.orig/contrib/hostmaint and bind4.9/contrib/hostmaint
Common subdirectories: bind4.9.orig/contrib/misc and bind4.9/contrib/misc
Common subdirectories: bind4.9.orig/contrib/named-lint and bind4.9/contrib/named-lint
Common subdirectories: bind4.9.orig/contrib/ninit and bind4.9/contrib/ninit
Common subdirectories: bind4.9.orig/contrib/nutshell and bind4.9/contrib/nutshell
Common subdirectories: bind4.9.orig/contrib/tic and bind4.9/contrib/tic
Common subdirectories: bind4.9.orig/contrib/ucsd and bind4.9/contrib/ucsd
Common subdirectories: bind4.9.orig/contrib/umich and bind4.9/contrib/umich
Common subdirectories: bind4.9.orig/contrib/tic/etc.named and bind4.9/contrib/tic/etc.named
diff -c -r bind4.9.orig/contrib/umich/dnsstats bind4.9/contrib/umich/dnsstats
*** bind4.9.orig/contrib/umich/dnsstats	Mon Apr 26 04:22:06 1993
--- bind4.9/contrib/umich/dnsstats	Thu Jul  8 14:30:38 1993
***************
*** 13,29 ****
  #
  #  DNS Statistics gatherer
  #  Author:  Bryan Beecher
! #  Last Modified:   3/10/93
  #
! #  To make use of this software, you need to be running the
! #  University of Michigan release of BIND 4.8.3.  This script
! #  may be used with standard BIND 4.8.3 or 4.8 if the ns_req()
! #  function is modified to log the IP address of the originator
! #  of each query, the domain name of the query, and the query
! #  type.
  #
- #  BIND 4.9 can also use this by turning on the QRYLOG option.
- #
  #  The assumption behind this script is that it will be run out
  #  of crontab daily just before some sort of syslog manager
  #  copies the current contents of LOGFILE elsewhere before
--- 13,23 ----
  #
  #  DNS Statistics gatherer
  #  Author:  Bryan Beecher
! #  Last Modified:   7/8/93
  #
! #  To make use of this software, you need to be running a copy of
! #  BIND 4.9 compiled with the QRYLOG option defined.
  #
  #  The assumption behind this script is that it will be run out
  #  of crontab daily just before some sort of syslog manager
  #  copies the current contents of LOGFILE elsewhere before
***************
*** 31,39 ****
  #  a LOGFILE that is not emptied daily, and in this case it
  #  would merely report the cumulative statistics.
  # -------------------------------------------------------------
! #  handy files
  # -------------------------------------------------------------
  LOGFILE=/var/log/named
  TMPFILE=/usr/tmp/.dnsstats$$
  OUTFILE=/usr/tmp/.dnsout$$
  ADDRFILE=/usr/tmp/.addrs$$
--- 25,70 ----
  #  a LOGFILE that is not emptied daily, and in this case it
  #  would merely report the cumulative statistics.
  # -------------------------------------------------------------
! 
  # -------------------------------------------------------------
+ #  C O N F I G U R A T I O N    S E C T I O N
+ # -------------------------------------------------------------
+ 
+ ##
+ ##  NOTE:  Ultrix users may want to change the first line
+ ##         of this script from /bin/sh to /bin/sh5.
+ ##
+ 
+ # -------------------------------------------------------------
+ #  Do we use 'getopts' or 'getopt'?
+ # -------------------------------------------------------------
+ GETOPT=getopts
+ 
+ # -------------------------------------------------------------
+ #  This is the name of the log.
+ # -------------------------------------------------------------
  LOGFILE=/var/log/named
+ 
+ # -------------------------------------------------------------
+ #  This is the program we use to look things up.
+ # -------------------------------------------------------------
+ # QUERYPROG="/usr/local/bin/query -t PTR"
+ # QUERYOPTIONS=""
+ QUERYPROG="/usr/local/bin/dig"
+ QUERYOPTIONS="PTR"
+ 
+ # -------------------------------------------------------------
+ #  This is the awk we use.
+ # -------------------------------------------------------------
+ AWK=/bin/awk
+ 
+ # -------------------------------------------------------------
+ #  E N D    O F    C O N F I G U R A T I O N    S E C T I O N
+ # -------------------------------------------------------------
+ 
+ # -------------------------------------------------------------
+ #  handy files
+ # -------------------------------------------------------------
  TMPFILE=/usr/tmp/.dnsstats$$
  OUTFILE=/usr/tmp/.dnsout$$
  ADDRFILE=/usr/tmp/.addrs$$
***************
*** 74,99 ****
  
  trap "rm -f $TMPFILE $OUTFILE $ADDRFILE $NAMEFILE $TYPEFILE $WEEKFILE ; exit 0" 0 1 2 3 15
  
! while getopts ac:d:f:nw ARG ; do
! 	case $ARG in
! 		a)	PRINTALL=1
! 			;;
! 		c)	STOPAT=$OPTARG
! 			;;
! 		d) 	LOGFILE=$LOGFILE"."$OPTARG
! 			;;
! 		f)	LOGFILE=$OPTARG
! 			;;
! 		n)	NONAMES=1
! 			;;
! 		w)	cat $LOGFILE* > $WEEKFILE
! 			LOGFILE=$WEEKFILE
! 			;;
  
! 	esac
! done
! shift `expr $OPTIND - 1`
  
  # -------------------------------------------------------------
  #  divide the log file into three files:
  #	one for source addrs of incoming querys
--- 105,181 ----
  
  trap "rm -f $TMPFILE $OUTFILE $ADDRFILE $NAMEFILE $TYPEFILE $WEEKFILE ; exit 0" 0 1 2 3 15
  
! gethostbyaddr() {
! 	QUERYNAME=`echo $ADDRESS | $AWK  '{ n = split($1, oct, ".")
! 	  printf("%s.%s.%s.%s.in-addr.arpa.\n", oct[4], oct[3], oct[2], oct[1])
! 	  }'`
! 	$QUERYPROG $QUERYNAME $QUERYOPTIONS 2>&1 | $AWK ' BEGIN {
! 	    msg = " ** Query failed ** "
! 	    }
! 	    {
! 	    if ($4 == "PTR")
! 		msg = substr($5, 1, length($5) - 1)
! 	    else if ($3 == "PTR")
! 		msg = substr($4, 1, length($4) - 1)
! 	    }
! 	    END {
! 		printf(" %6d  %-39s [%s]\n", count, msg, address)
! 	    }' count=$COUNT address=$ADDRESS - ;
! }
  
! if [ $GETOPT = "getopts" ] ; then
! 	while getopts ac:d:f:nw ARG ; do
! 		case $ARG in
! 			a)	PRINTALL=1
! 				;;
! 			c)	STOPAT=$OPTARG
! 				;;
! 			d) 	LOGFILE=$LOGFILE"."$OPTARG
! 				;;
! 			f)	LOGFILE=$OPTARG
! 				;;
! 			n)	NONAMES=1
! 				;;
! 			w)	cat $LOGFILE* > $WEEKFILE
! 				LOGFILE=$WEEKFILE
! 				;;
  
+ 		esac
+ 	done
+ 	shift `expr $OPTIND - 1`
+ else
+ 	set -- `getopt ac:d:f:nw $*`
+ 	if [ $? != 0 ] ; then
+ 		exit 2
+ 	fi
+ 	for ARG in $* ; do
+ 		case $ARG in
+ 			-a)	PRINTALL=1
+ 				shift
+ 				;;
+ 			-c)	STOPAT=$2
+ 				shift 2
+ 				;;
+ 			-d) 	LOGFILE=$LOGFILE"."$2
+ 				shift 2
+ 				;;
+ 			-f)	LOGFILE=$2
+ 				shift 2
+ 				;;
+ 			-n)	NONAMES=1
+ 				shift
+ 				;;
+ 			-w)	cat $LOGFILE* > $WEEKFILE
+ 				LOGFILE=$WEEKFILE
+ 				shift
+ 				;;
+ 			--)	shift
+ 				break
+ 				;;
+ 		esac
+ 	done
+ fi
+ 
  # -------------------------------------------------------------
  #  divide the log file into three files:
  #	one for source addrs of incoming querys
***************
*** 100,106 ****
  #	one for domain names that were queried upon
  #	one for query types
  # -------------------------------------------------------------
! awk '
  {
  	if ((n == 0) && ($5 == "last"))
  		next
--- 182,188 ----
  #	one for domain names that were queried upon
  #	one for query types
  # -------------------------------------------------------------
! $AWK '
  {
  	if ((n == 0) && ($5 == "last"))
  		next
***************
*** 124,131 ****
  # -------------------------------------------------------------
  #  Print some general information
  # -------------------------------------------------------------
! echo "DNS stats for" `hostname` "for period ending" `ls -l $LOGFILE | awk '{ print $5, $6, $7 }'`
! echo "Total queries received: " `wc -l $ADDRFILE | awk '{ print $1}'`
  echo
  echo "Part I -- query sources"
  echo
--- 206,213 ----
  # -------------------------------------------------------------
  #  Print some general information
  # -------------------------------------------------------------
! echo "DNS stats for" `hostname` "for period ending" `ls -l $LOGFILE | $AWK '{ print $5, $6, $7 }'`
! echo "Total queries received: " `wc -l $ADDRFILE | $AWK '{ print $1}'`
  echo
  echo "Part I -- query sources"
  echo
***************
*** 147,160 ****
  		if [ $? -ne 0 ] ; then
  			break
  		fi
! 		host $ADDRESS 2>&1 | awk '{
! 			if (NF == 1)
! 				printf(" %6d  %-39s [%s]\n", count, $1, address)
! 			else {
! 				i = split($0, msg, ":")
! 				printf(" %6d  ** %-33s ** [%s]\n", count, msg[2], address)
! 			}
! 		}' count=$COUNT address=$ADDRESS -
  	done < $ADDRFILE
  else
  	echo " Number  IP address"
--- 229,235 ----
  		if [ $? -ne 0 ] ; then
  			break
  		fi
! 		gethostbyaddr
  	done < $ADDRFILE
  else
  	echo " Number  IP address"
***************
*** 161,169 ****
  	echo " ------  ----------"
  	sort $ADDRFILE | uniq -c | sort -n -r > $TMPFILE
  	if [ $PRINTALL -eq 1 ] ; then
! 		awk '{ printf(" %6d  [%s]\n", $1, $2) }' $TMPFILE
  	else
! 		head -$STOPAT $TMPFILE | awk '{ printf(" %5d  [%s]\n", $1, $2) }'
  	fi
  fi
  
--- 236,244 ----
  	echo " ------  ----------"
  	sort $ADDRFILE | uniq -c | sort -n -r > $TMPFILE
  	if [ $PRINTALL -eq 1 ] ; then
! 		$AWK '{ printf(" %6d  [%s]\n", $1, $2) }' $TMPFILE
  	else
! 		head -$STOPAT $TMPFILE | $AWK '{ printf(" %5d  [%s]\n", $1, $2) }'
  	fi
  fi
  
***************
*** 177,185 ****
  echo " ------  ------------"
  sort $NAMEFILE | uniq -c | sort -n -r > $TMPFILE
  if [ $PRINTALL -eq 1 ] ; then
! 	awk '{ printf(" %6d  %s\n", $1, $2) }' $TMPFILE
  else
! 	head -$STOPAT $TMPFILE | awk '{ printf(" %6d  %s\n", $1, $2) }'
  fi
  
  # -------------------------------------------------------------
--- 252,260 ----
  echo " ------  ------------"
  sort $NAMEFILE | uniq -c | sort -n -r > $TMPFILE
  if [ $PRINTALL -eq 1 ] ; then
! 	$AWK '{ printf(" %6d  %s\n", $1, $2) }' $TMPFILE
  else
! 	head -$STOPAT $TMPFILE | $AWK '{ printf(" %6d  %s\n", $1, $2) }'
  fi
  
  # -------------------------------------------------------------
***************
*** 192,200 ****
  echo " ------  ----"
  sort $TYPEFILE | uniq -c | sort -n -r > $TMPFILE
  if [ $PRINTALL -eq 1 ] ; then
! 	awk '{ printf(" %6d  %s\n", $1, $2) }' $TMPFILE
  else
! 	head -$STOPAT $TMPFILE | awk '{ printf(" %6d  %s\n", $1, $2) }'
  fi
  
  # -------------------------------------------------------------
--- 267,275 ----
  echo " ------  ----"
  sort $TYPEFILE | uniq -c | sort -n -r > $TMPFILE
  if [ $PRINTALL -eq 1 ] ; then
! 	$AWK '{ printf(" %6d  %s\n", $1, $2) }' $TMPFILE
  else
! 	head -$STOPAT $TMPFILE | $AWK '{ printf(" %6d  %s\n", $1, $2) }'
  fi
  
  # -------------------------------------------------------------
diff -c -r bind4.9.orig/contrib/umich/query.c bind4.9/contrib/umich/query.c
*** bind4.9.orig/contrib/umich/query.c	Mon Apr 26 04:22:17 1993
--- bind4.9/contrib/umich/query.c	Mon May 17 11:37:02 1993
***************
*** 171,177 ****
  		if (res_query(name, class, type, answer, len) < 0) {
  			hp = (HEADER *) answer;
  			if ((hp->rcode == 0) && (hp->ancount > 0))
! 				p_query(answer);
  			else
  				fprintf(stderr, "Query failed (h_errno = %d) : %s\n", 
  						h_errno, h_errlist[h_errno]);
--- 171,177 ----
  		if (res_query(name, class, type, answer, len) < 0) {
  			hp = (HEADER *) answer;
  			if ((hp->rcode == 0) && (hp->ancount > 0))
! 				__p_query(answer);
  			else
  				fprintf(stderr, "Query failed (h_errno = %d) : %s\n", 
  						h_errno, h_errlist[h_errno]);
***************
*** 181,192 ****
  	else if (res_search(name, class, type, answer, len) < 0) {
  		hp = (HEADER *) answer;
  		if ((hp->rcode == 0) && (hp->ancount > 0))
! 			p_query(answer);
  		else
  			fprintf(stderr, "Query failed (h_errno = %d) : %s\n", 
  						h_errno, h_errlist[h_errno]);
  		exit(-1);
  	}
! 	p_query(answer);
  	exit(0);
  }
--- 181,192 ----
  	else if (res_search(name, class, type, answer, len) < 0) {
  		hp = (HEADER *) answer;
  		if ((hp->rcode == 0) && (hp->ancount > 0))
! 			__p_query(answer);
  		else
  			fprintf(stderr, "Query failed (h_errno = %d) : %s\n", 
  						h_errno, h_errlist[h_errno]);
  		exit(-1);
  	}
! 	__p_query(answer);
  	exit(0);
  }
diff -c -r bind4.9.orig/contrib/umich/zt bind4.9/contrib/umich/zt
*** bind4.9.orig/contrib/umich/zt	Mon Apr 26 04:22:21 1993
--- bind4.9/contrib/umich/zt	Thu Jul  8 14:01:15 1993
***************
*** 119,129 ****
  	#  have run out of subdomains, we're done
  	#----------------------------------------------------
  	if [ $DONE = 1 ] ; then
! 		if [ -s /tmp/zt.out.$$ ] ; then
! 			cat /tmp/zt.out.$$
! 		else
! 			echo "Could not perform a zone transfer of $1"
! 		fi
  		rm -f /tmp/zt.out.$$
  		exit 0
  	else
--- 119,125 ----
  	#  have run out of subdomains, we're done
  	#----------------------------------------------------
  	if [ $DONE = 1 ] ; then
! 		cat /tmp/zt.out.$$
  		rm -f /tmp/zt.out.$$
  		exit 0
  	else
Common subdirectories: bind4.9.orig/doc/BOG and bind4.9/doc/BOG
diff -c -r bind4.9.orig/doc/BOG/files.me bind4.9/doc/BOG/files.me
*** bind4.9.orig/doc/BOG/files.me	Sun May  2 20:23:56 1993
--- bind4.9/doc/BOG/files.me	Fri May 21 14:09:18 1993
***************
*** 580,585 ****
--- 580,597 ----
  The \fIAddress\fP record, \fIA\fP, lists the address for a given machine. 
  The name field is the machine name and the address is the network address.
  There should be one \fIA\fP record for each address of the machine. 
+ .sh 3 "SA - Shuffle Address"
+ .TS
+ l l l l l.
+ \fI{name}	{ttl}	addr-class	SA	address\fP
+ archive		IN	SA	141\fB.\fP211\fB.\fP165\fB.\fP41
+ 		IN	SA	141\fB.\fP211\fB.\fP32\fB.\fP2
+ .TE
+ The \fIShuffle Address\fP record, \fISA\fP, lists the address for a given
+ machine as above.  Unlike the \fIAddress\fP record, records of this type
+ are randomized (shuffled) before being returned.  The records are
+ returned as simple \fIAddress\fP records so that client software does not
+ need to be modified.
  .sh 3 "HINFO - Host Information"
  .TS
  l l l l l l. 
Common subdirectories: bind4.9.orig/include/arpa and bind4.9/include/arpa
Common subdirectories: bind4.9.orig/include/sys and bind4.9/include/sys
diff -c -r bind4.9.orig/include/arpa/nameser.h bind4.9/include/arpa/nameser.h
*** bind4.9.orig/include/arpa/nameser.h	Mon May 17 06:00:15 1993
--- bind4.9/include/arpa/nameser.h	Mon May 17 15:27:16 1993
***************
*** 135,145 ****
--- 135,147 ----
  #define T_MX		15		/* mail routing information */
  #define T_TXT		16		/* text strings */
  #define	T_RP		17		/* responsible person */
+ #define T_AFSDB		18		/* AFS cell database */
  	/* non standard */
  #define T_UINFO		100		/* user (finger) information */
  #define T_UID		101		/* user ID */
  #define T_GID		102		/* group ID */
  #define T_UNSPEC	103		/* Unspecified format (binary data) */
+ #define T_SA		104		/* shuffle address */
  	/* Query type values which do not appear in resource records */
  #define T_AXFR		252		/* transfer zone of authority */
  #define T_MAILB		253		/* transfer mailbox records */
diff -c -r bind4.9.orig/man/named.8 bind4.9/man/named.8
*** bind4.9.orig/man/named.8	Mon May 17 04:45:57 1993
--- bind4.9/man/named.8	Fri May 21 13:59:45 1993
***************
*** 98,103 ****
--- 98,110 ----
  .B \-q
  Trace all incoming queries if \fInamed\fP has been compiled with
  \fIQRYLOG\fP defined.
+ .TP
+ .B \-s
+ Use this flag if \fInamed\fP has been compiled with
+ \fISHUFFLE_ADDRS\fP defined, and both you and all of your secondary
+ nameservers know about SA records.  If this flag is not present,
+ and you use SA records, then they are passed on as simple A records
+ by the zone transfer program.
  .PP
  Any additional argument is taken as the name of the boot file.
  If multiple boot files are specified, only the last is used.
diff -c -r bind4.9.orig/named/db.h bind4.9/named/db.h
*** bind4.9.orig/named/db.h	Sun May  2 20:24:37 1993
--- bind4.9/named/db.h	Mon May 17 14:55:49 1993
***************
*** 102,107 ****
--- 102,111 ----
   */
  #define DB_F_HINT       0x01	/* databuf belongs to fcachetab */
  
+ #ifdef SHUFFLE_ADDRS
+ #define DB_F_SHUFFLE	0x02	/* records should be shuffled */
+ #endif
+ 
  #ifdef CRED
  /*
   * d_cred definitions
diff -c -r bind4.9.orig/named/db_dump.c bind4.9/named/db_dump.c
*** bind4.9.orig/named/db_dump.c	Sun May  2 20:24:38 1993
--- bind4.9/named/db_dump.c	Mon May 17 11:01:06 1993
***************
*** 480,485 ****
--- 480,486 ----
  				break;
  
  			case T_MX:
+ 			case T_AFSDB:
  				GETSHORT(n, cp);
  				fprintf(fp,"%lu", n);
  				fprintf(fp," %s.", cp);
diff -c -r bind4.9.orig/named/db_load.c bind4.9/named/db_load.c
*** bind4.9.orig/named/db_load.c	Sun May  2 20:24:39 1993
--- bind4.9/named/db_load.c	Mon May 17 14:58:49 1993
***************
*** 121,128 ****
--- 121,132 ----
  	"uinfo",	T_UINFO,
  	"txt",		T_TXT,
  	"rp",		T_RP,
+ 	"afsdb",	T_AFSDB,
  	"uid",		T_UID,
  	"gid",		T_GID,
+ #ifdef SHUFFLE_ADDRS
+ 	"sa",		T_SA,
+ #endif
  #ifdef notdef
  	"any",		T_ANY,		/* any is a QTYPE, not TYPE */
  #endif
***************
*** 334,339 ****
--- 338,349 ----
  			 * based on the type and pack into 'data'.
  			 */
  			switch (type) {
+ #ifdef SHUFFLE_ADDRS
+ 			case T_SA:
+ 				type = T_A;
+ 				dataflags |= DB_F_SHUFFLE;
+ 				/* now fall through */
+ #endif
  			case T_A:
  				n = ntohl((u_int32_t)inet_addr((char *)buf));
  				cp = data;
***************
*** 467,472 ****
--- 477,483 ----
  				n = strlen((char *)data) + 1;
  				break;
  			case T_MX:
+ 			case T_AFSDB:
  				n = 0;
  				cp = buf;
  				while (isdigit(*cp))
***************
*** 560,565 ****
--- 571,579 ----
  				(u_char *)data, (int)n);
  			dp->d_zone = zp - zones;
  			dp->d_flags = dataflags;
+ #ifdef SHUFFLE_ADDRS
+ 			dataflags &= ~DB_F_SHUFFLE;
+ #endif
  #ifdef CRED
  			dp->d_cred = DB_C_AUTH;
  #endif /*CRED*/
diff -c -r bind4.9.orig/named/db_update.c bind4.9/named/db_update.c
*** bind4.9.orig/named/db_update.c	Sun May  2 20:24:41 1993
--- bind4.9/named/db_update.c	Mon May 17 11:02:42 1993
***************
*** 530,535 ****
--- 530,536 ----
  		return bcmp(cp1, cp2, sizeof(u_int32_t) * 5);
  	
  	case T_MX:
+ 	case T_AFSDB:
  		cp1 = dp1->d_data;
  		cp2 = dp2->d_data;
  		if (*cp1++ != *cp2++ || *cp1++ != *cp2++)	/* cmp prio */
diff -c -r bind4.9.orig/named/named-xfer.c bind4.9/named/named-xfer.c
*** bind4.9.orig/named/named-xfer.c	Mon May 17 06:01:13 1993
--- bind4.9/named/named-xfer.c	Tue Jul  6 11:12:20 1993
***************
*** 144,150 ****
  		c += (close(fd) == 0);
  	}
  #ifdef LOG_DAEMON
! 	openlog("named-xfer", LOG_PID|LOG_CONS, LOG_DAEMON);
  #else
  	openlog("named-xfer", LOG_PID);
  #endif
--- 144,150 ----
  		c += (close(fd) == 0);
  	}
  #ifdef LOG_DAEMON
! 	openlog("named-xfer", LOG_PID|LOG_CONS, LOG_LOCAL2);
  #else
  	openlog("named-xfer", LOG_PID);
  #endif
***************
*** 986,991 ****
--- 986,994 ----
  	 * Convert the resource record data into the internal database format.
  	 */
  	switch (type) {
+ #ifdef SHUFFLE_ADDRS
+ 	case T_SA:
+ #endif
  	case T_A:
  	case T_WKS:
  	case T_HINFO:
***************
*** 1046,1051 ****
--- 1049,1055 ----
  		break;
  
  	case T_MX:
+ 	case T_AFSDB:
  		/* grab preference */
  		bcopy((char *) cp, (char *) data, sizeof(u_short));
  		cp1 = data + sizeof(u_short);
***************
*** 1159,1164 ****
--- 1163,1171 ----
  	 */
  	switch (type) {
  
+ #ifdef SHUFFLE_ADDRS
+ 	case T_SA:
+ #endif
  	case T_A:
  		switch (class) {
  		case C_IN:
***************
*** 1223,1228 ****
--- 1230,1236 ----
  		break;
  
  	case T_MX:
+ 	case T_AFSDB:
  		GETSHORT(n, cp);
  		(void) fprintf(dbfp, "%lu", n);
  		(void) fprintf(dbfp, " %s.\n", cp);
***************
*** 1233,1243 ****
  		(void) putc('"', dbfp);
  		while (cp < cp1) {
  			if (i = *cp++) {
! 				for (j = i ; j > 0 && cp < cp1 ; j--)
  					if ((*cp == '\n') || (*cp == '"')) {
  						(void) putc('\\', dbfp);
  					}
  					(void) putc(*cp++, dbfp);
  			}
  		}
  		(void) fputs("\"\n", dbfp);
--- 1241,1252 ----
  		(void) putc('"', dbfp);
  		while (cp < cp1) {
  			if (i = *cp++) {
! 				for (j = i ; j > 0 && cp < cp1 ; j--) {
  					if ((*cp == '\n') || (*cp == '"')) {
  						(void) putc('\\', dbfp);
  					}
  					(void) putc(*cp++, dbfp);
+ 				}
  			}
  		}
  		(void) fputs("\"\n", dbfp);
diff -c -r bind4.9.orig/named/ns.h bind4.9/named/ns.h
*** bind4.9.orig/named/ns.h	Sun May  2 20:24:45 1993
--- bind4.9/named/ns.h	Wed Jun 16 11:51:03 1993
***************
*** 170,175 ****
--- 170,178 ----
  	char	*q_cmsg;		/* the cname message */
  	struct	qstream *q_stream;	/* TCP stream, null if UDP */
  	int	q_system;		/* boolean, system query */
+ #ifdef LAME_DELEGATION
+ 	char	q_domain[MAXDNAME];	/* domain for servers we are querying */
+ #endif /* LAME_DELEGATION */
  };
  
  #define	Q_NEXTADDR(qp,n)	\
diff -c -r bind4.9.orig/named/ns_forw.c bind4.9/named/ns_forw.c
*** bind4.9.orig/named/ns_forw.c	Sun May  2 20:24:46 1993
--- bind4.9/named/ns_forw.c	Fri Jun 18 12:03:47 1993
***************
*** 99,106 ****
--- 99,111 ----
   * dangerous, such as fwd to ourselves or fwd to the host that asked us.
   * (no action is taken on errors and qpp is not filled in.)
   */
+ #ifdef LAME_DELEGATION
  int
+ ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np)
+ #else /* LAME DELEGATION */
+ int
  ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname)
+ #endif /* LAME DELEGATION */
  	struct databuf *nsp[];
  	u_char *msg;
  	int msglen;
***************
*** 109,114 ****
--- 114,122 ----
  	int dfd;
  	struct qinfo **qpp;
  	char *dname;
+ #ifdef LAME_DELEGATION
+         struct namebuf *np;
+ #endif /* LAME DELEGATION */
  {
  	register struct qinfo *qp;
  	HEADER *hp;
***************
*** 143,148 ****
--- 151,159 ----
  	}
  
  	qp = qnew();
+ #ifdef LAME_DELEGATION
+         getname(np, qp->q_domain, sizeof(qp->q_domain));
+ #endif /* LAME DELEGATION */
  	qp->q_from = *fp;	/* nslookup wants to know this */
  	if ((n = nslookup(nsp, qp, dname, "ns_forw")) < 0) {
  #ifdef DEBUG
diff -c -r bind4.9.orig/named/ns_main.c bind4.9/named/ns_main.c
*** bind4.9.orig/named/ns_main.c	Sun May  2 20:24:47 1993
--- bind4.9/named/ns_main.c	Thu Jul  8 14:31:29 1993
***************
*** 159,164 ****
--- 159,168 ----
  int qrylog = 0;
  #endif /*QRYLOG*/
  
+ #ifdef SHUFFLE_ADDRS
+ int pass_sa_rrs = 0;
+ #endif
+ 
  int	priming = 0;			/* is cache being primed */
  
  #ifdef SO_RCVBUF
***************
*** 316,321 ****
--- 320,330 ----
  				case 'q':
  					qrylog = 1;
  					break;
+ #ifdef SHUFFLE_ADDRS
+ 				case 's':
+ 					pass_sa_rrs = 1;
+ 					break;
+ #endif
  				default:
  					usage();
  				}
***************
*** 360,366 ****
  #endif /*WANT_PIDFILE*/
  
  	syslog(LOG_NOTICE, "starting");
- 
  	_res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
  
  	nsaddr.sin_family = AF_INET;
--- 369,374 ----
diff -c -r bind4.9.orig/named/ns_req.c bind4.9/named/ns_req.c
*** bind4.9.orig/named/ns_req.c	Sun May  2 20:24:48 1993
--- bind4.9/named/ns_req.c	Fri Jun 18 12:05:04 1993
***************
*** 109,114 ****
--- 109,117 ----
  #ifdef XFRNETS
  extern struct netinfo *xfrnets;
  #endif
+ #ifdef SHUFFLE_ADDRS
+ int found_shuffle;
+ #endif
  
  int stale(), make_rr(), doaddinfo(), doaddauth();
  void ns_req(), fwritemsg(), getname(), doaxfr(), startxfr();
***************
*** 393,398 ****
--- 396,408 ----
  			    founddata, cname);
  		}
  #endif
+ #ifdef SHUFFLE_ADDRS
+ 		if (found_shuffle) {
+ 			found_shuffle = 0;
+ 			shuffle_response(answers, count, cp);
+ 		}
+ 		else
+ #endif
  		if ((lp = local(from)) != NULL) 
  			sort_response(answers, count, lp, cp);
  		if (type == T_AXFR) {
***************
*** 492,498 ****
--- 502,512 ----
  				(char *)NULL, 0, NULL, (char *)msg,
  				msglen+buflen);
  		}
+ #ifdef LAME_DELEGATION
+ 		n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp, dname, np);
+ #else /* LAME DELEGATION */
  		n = ns_forw(nsp, msg, msglen, from, qsp, dfd, &qp, dname);
+ #endif /* LAME DELEGATION */
  		if (n != FW_OK && cname)
  			free(omsg);
  		switch (n) {
***************
*** 944,949 ****
--- 958,964 ----
  		break;
  
  	case T_MX:
+ 	case T_AFSDB:
  		/* cp1 == our data/ cp == data of RR */
  		cp1 = dp->d_data;
  
***************
*** 1196,1201 ****
--- 1211,1219 ----
  	char dname[MAXDNAME];
  	HEADER *hp = (HEADER *) msg;
  	int fndns;
+ #ifdef SHUFFLE_ADDRS
+ 	extern int pass_sa_rrs;
+ #endif
  
  #ifdef DEBUG
  	if (debug && (np == top))
***************
*** 1277,1282 ****
--- 1295,1307 ----
  			continue;
  		if (dp->d_zone == 0 || stale(dp))
  			continue;
+ #ifdef SHUFFLE_ADDRS
+ 		if ((dp->d_flags & DB_F_SHUFFLE) &&
+ 		   pass_sa_rrs && (dp->d_type == T_A)) {
+ 			syslog(LOG_INFO, "Found a shuffle record");
+ 			dp->d_type = T_SA;
+ 		}
+ #endif
  		if ((n = make_rr(dname, dp, cp, sizeof(msg)-sizeof(HEADER), 0)) < 0)
  			continue;
  		fwritemsg(rfp, msg, n + sizeof(HEADER));
***************
*** 1666,1668 ****
--- 1691,1754 ----
  		exit(0);
  	}
  }
+ 
+ #ifdef SHUFFLE_ADDRS
+ 
+ shuffle_response(cp, count, eom)
+ register u_char *cp;
+ int count;
+ u_char *eom;
+ {
+ #define ITEMS_TO_SHUFFLE 32 /* arbitrary -- can make it higher */
+ 
+ 	register int i, j, c;
+ 	int type, class, dlen, n, A_recs = 0;
+ 	struct in_addr inaddr[ITEMS_TO_SHUFFLE];
+ 	u_char *rr[ITEMS_TO_SHUFFLE];
+ 
+ #ifdef DEBUG
+ 	if (debug > 2) 
+ 		fprintf(ddt,"shuffle_rrs(0x%x, %d)\n", cp, count);
+ #endif DEBUG
+ 	if (count == 1) 
+ 		return;		/* nothing to randomize */
+ 	if (count > ITEMS_TO_SHUFFLE) {
+ #ifdef DEBUG
+ 		if (debug > 2) 
+ 			fprintf(ddt, "Too many records to shuffle\n");
+ 		return;
+ 	}
+ #endif DEBUG
+ 
+ 	/* gather up the A records */
+ 	for (c = count, i = 0; c > 0; --c, i++) {
+ 		n = dn_skipname(cp, eom);
+ 		if (n < 0) return;		/* bogus, stop processing */
+ 	    	cp += n;
+ 	    	if (cp + QFIXEDSZ > eom) return;
+ 	    	GETSHORT(type, cp);
+ 		if (type != T_A)
+ 			continue;
+ 	    	GETSHORT(class, cp);
+ 	    	cp += sizeof(u_long);
+ 	    	GETSHORT(dlen, cp);
+ 	    	if (dlen > eom - cp) return;	/* bogus, stop processing */
+ 		rr[i] = cp;
+ 		bcopy(cp, (char *) &(inaddr[i]), sizeof(struct in_addr));
+ 		cp += dlen;
+ 		A_recs++;
+ 	}
+ 	if (A_recs < 2)
+ 		return;
+ 
+ 	/* shuffle up the addresses */
+ 	if ((c = rand() % A_recs) == 0)
+ 		return;
+ 	for (i = 0, j = A_recs; j > 0; j--, i++) {
+ 		bcopy((char *) &(inaddr[c]), rr[i], sizeof(struct in_addr));
+ 		if (++c == A_recs) 
+ 			c = 0;
+ 	}
+ 	return;
+ }
+ #endif
diff -c -r bind4.9.orig/named/ns_resp.c bind4.9/named/ns_resp.c
*** bind4.9.orig/named/ns_resp.c	Sun May  2 20:24:49 1993
--- bind4.9/named/ns_resp.c	Fri Jun 18 12:01:12 1993
***************
*** 94,99 ****
--- 94,103 ----
  		wanted(), add_data();
  struct qinfo	*sysquery();
  
+ #ifdef SHUFFLE_ADDRS
+ extern int found_shuffle;
+ #endif
+ 
  void
  ns_resp(msg, msglen)
  	u_char *msg;
***************
*** 172,177 ****
--- 176,219 ----
  		return;
  	}
  
+ #ifdef LAME_DELEGATION
+         /*
+          *  Non-authoritative, no answer, no error
+          */
+         if (hp->rcode == NOERROR && !hp->aa && ntohs(hp->ancount) == 0 &&
+              ntohs(hp->nscount) > 0) {
+                 char qname[MAXDNAME];
+ 
+                 cp = msg + sizeof(HEADER);
+                 dpp = dnptrs;
+                 *dpp++ = msg;
+                 if ((*cp & INDIR_MASK) == 0)
+                         *dpp++ = cp;
+                 *dpp = NULL;
+                 if (hp->qdcount) {
+                         n = dn_expand(msg, msg + msglen, cp, qname, sizeof(qname));
+                         if (n <= 0)
+                                 goto formerr;
+                         cp += n;
+                         GETSHORT(type, cp);
+                         GETSHORT(class, cp);
+                         if (cp - msg > msglen)
+                                 goto formerr;
+                 }
+                 if ((n = dn_expand(msg, msg + msglen, cp, name, sizeof(name))) < 0) {
+                         goto formerr;
+                 }
+                 cp += n;
+                 GETSHORT(type, cp);
+                 if ((type == T_NS) && (strlen(name) <= strlen(qp->q_domain)) && (strlen(name) > 0)) {
+                         syslog(LOG_WARNING, "Lame delegation to '%s' received from %s (purported server for '%s') on query on name [%s]\n",
+                                 name, inet_ntoa(from_addr.sin_addr),
+                                 qp->q_domain, qname);
+                         return;
+                 }
+         }
+ #endif /* LAME_DELEGATION */
+ 
  #ifdef ALLOW_UPDATES
  	if ( (hp->rcode == NOERROR) &&
  	     (hp->opcode == UPDATEA || hp->opcode == UPDATED ||
***************
*** 718,723 ****
--- 760,768 ----
  	qp->q_naddr = 0;
  	qp->q_curaddr = 0;
  	qp->q_fwd = fwdtab;
+ #ifdef LAME_DELEGATION
+         getname(np, qp->q_domain, sizeof(qp->q_domain));
+ #endif /* LAME_DELEGATION */
  	if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
  #ifdef DEBUG
  		if (debug >= 3)
***************
*** 980,985 ****
--- 1025,1031 ----
  		break;
  
  	case T_MX:
+ 	case T_AFSDB:
  		/* grab preference */
  		bcopy(cp,data,sizeof(u_short));
  		cp1 = data + sizeof(u_short);
***************
*** 1763,1768 ****
--- 1809,1818 ----
  				foundstale++;
  			continue;
  		}
+ #ifdef SHUFFLE_ADDRS
+ 		if (dp->d_flags & DB_F_SHUFFLE)
+ 			found_shuffle = 1;
+ #endif
  		if ((n = make_rr(*dnamep, dp, (u_char *)cp, buflen, 1)) < 0) {
  			hp->tc = 1;
  			*countp = count;
diff -c -r bind4.9.orig/res/res_debug.c bind4.9/res/res_debug.c
*** bind4.9.orig/res/res_debug.c	Mon May 17 06:01:21 1993
--- bind4.9/res/res_debug.c	Mon May 24 11:28:03 1993
***************
*** 65,70 ****
--- 65,71 ----
  #include <resolv.h>
  #include <stdio.h>
  #include "../conf/portability.h"
+ #include "../conf/options.h"
  
  void __fp_query();
  char *__p_class(), *__p_time(), *__p_type();
***************
*** 348,354 ****
  	char name[MAXDNAME];
  	int n;
  
! 	if ((n = dn_expand((u_char *)msg, (u_char *)msg + 512, (u_char *)cp,
  	    (u_char *)name, sizeof(name))) < 0)
  		return (NULL);
  	if (name[0] == '\0') {
--- 349,361 ----
  	char name[MAXDNAME];
  	int n;
  
! 	/*
! 	 *  Cannot assume that the message is 512 bytes long.  It could
! 	 *  be longer for TCP-based messages.  A better "sanity check"
! 	 *  here would be to make sure that cp does not get advanced more
! 	 *  than MAXCDNAME (maximum size of a compressed domain name) bytes.
! 	 */
! 	if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME, (u_char *)cp,
  	    (u_char *)name, sizeof(name))) < 0)
  		return (NULL);
  	if (name[0] == '\0') {
***************
*** 367,373 ****
  	char name[MAXDNAME];
  	int n, len;
  
! 	if ((n = dn_expand((u_char *)msg, (u_char *)msg + 512, (u_char *)cp,
  	    (u_char *)name, sizeof(name))) < 0)
  		return (NULL);
  	if (name[0] == '\0') {
--- 374,380 ----
  	char name[MAXDNAME];
  	int n, len;
  
! 	if ((n = dn_expand((u_char *)msg, (u_char *)cp + MAXCDNAME, (u_char *)cp,
  	    (u_char *)name, sizeof(name))) < 0)
  		return (NULL);
  	if (name[0] == '\0') {
***************
*** 483,488 ****
--- 490,496 ----
  		break;
  
  	case T_MX:
+ 	case T_AFSDB:
  		fprintf(file,"\t%d ", _getshort(cp));
  		cp += sizeof(u_short);
  		cp = p_fqname(cp, msg, file);
***************
*** 629,634 ****
--- 637,644 ----
  		return("TXT");
  	case T_RP:		/* responsible person */
  		return("RP");
+ 	case T_AFSDB:		/* AFS cell database */
+ 		return("AFSDB");
  	case T_AXFR:		/* zone transfer */
  		return("AXFR");
  	case T_MAILB:		/* mail box */
***************
*** 647,652 ****
--- 657,671 ----
  	case T_UNSPEC:
  		return("UNSPEC");
  #endif /* ALLOW_T_UNSPEC */
+ #ifdef SHUFFLE_ADDRS
+ 	/*
+ 	 *  This is only used by named-xfer, and only in the case where
+ 	 *  the -s flag is in use on the master server (and so SA records 
+ 	 *  are sent rather than A records).
+ 	 */
+ 	case T_SA:		/* shuffle address */
+ 		return("SA");
+ #endif
  	default:
  		(void)sprintf(nbuf, "%d", type);
  		return(nbuf);
diff -c -r bind4.9.orig/res/res_query.c bind4.9/res/res_query.c
*** bind4.9.orig/res/res_query.c	Sun May  2 19:58:19 1993
--- bind4.9/res/res_query.c	Fri May 21 14:22:08 1993
***************
*** 182,187 ****
--- 182,198 ----
  	if (n == 0 && (cp = __hostalias(name)))
  		return (res_query(cp, class, type, answer, anslen));
  
+ #ifdef TRY_AS_IS
+ 	/*
+ 	 *      If there is more than one dot in the name already,
+ 	 *	let's just give it a try 'as is'.
+ 	 */
+ 	if (n > 1) {
+ 		if ((ret = res_query(name, class, type, answer, anslen)) > 0)
+ 			return(ret);
+ 	}
+ #endif
+ 
  	/*
  	 * We do at least one level of search if
  	 *	- there is no dot and RES_DEFNAME is set, or
Common subdirectories: bind4.9.orig/tools/nslookup and bind4.9/tools/nslookup
